/*
 *  Copyright 2012 SerGenis. All rights reserved.
 */
package com.sergenis.util;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author SerGenis
 */
public class PropertiesStore
    extends Properties {

    private static final String KEY_PATTERN = "\\$\\{\\w{1,}(\\.{1}\\w+)*\\}";

    public PropertiesStore() {
    }

    public PropertiesStore(Properties defaults) {
	super(defaults);
    }

    public PropertiesStore(String resource)
	throws IOException {
	this(PropertiesStore.class.getResource(resource));
    }

    public PropertiesStore(java.net.URL url)
	throws IOException {
	this(PropertiesIO.read(url));
    }

    public PropertiesStore(java.io.File file)
	throws FileNotFoundException, IOException {
	this(PropertiesIO.read(file));
    }

    public synchronized void putAll(Properties prop) {
	Iterator<Map.Entry<Object, Object>> set = prop.entrySet().iterator();
	Map<Object, Object> map = new HashMap<Object, Object>();
	while (set.hasNext()) {
	    Map.Entry<Object, Object> entry = set.next();
	    map.put(entry.getKey(), entry.getValue());
	}
	super.putAll(map);
    }

    @Override
    public String getProperty(String key) {
	// Se obtiene la propiedad nativa. Sin tratar
	String prop = super.getProperty(key);
	// Si el valor de la propiedad es nulo se retorna nulo.
	if (prop == null) return null;
	// Se crear la instancia del pattern para alalizar la
	// cadena de la propiedad pasando como argumento KEY_PATTERN
	Pattern patron = Pattern.compile(KEY_PATTERN);
	// Creamos una referencia a un objeto Matcher que sera el encargado de
	// buscar las coincidencias establecidas por el Pattern.
	Matcher matcher = null;

	// Se hace la instancia de Matcher para analizar
	// el texto de la propiedad.
	matcher = patron.matcher(prop);
	// Un String builder para ir guardando el texto resultante.
	StringBuffer buff = new StringBuffer();

	while (matcher.find()) {
	    // Se obtiene la propiedad encontrada a remplazar.
	    String subProp = matcher.group();
	    // Se quita el signo de pesos y las llaves para obtener el nombre
	    subProp = subProp.substring(2, subProp.length() - 1);
	    // Se obtiene el valor de la propiedad
	    // este metodo es recursivo de forma indirecta.
	    // public String getProperty(String key, String defaultValue) {
	    //     String val = getProperty(key); <--- #Resursividad
	    //     return (val == null) ? defaultValue : val; }
	    subProp = getProperty(subProp, "");
	    matcher.appendReplacement(buff, subProp);
	};
	matcher.appendTail(buff);
	return buff.toString();
    }

    public void listRemplace(PrintStream out) {
	out.println("-- listing properties remplace--");
	java.util.Enumeration<Object> e = this.keys();
	for (; e.hasMoreElements();) {
	    String key = (String) e.nextElement();
	    String val = (String) getProperty(key);
	    if (val.length() > 40) val = val.substring(0, 37) + "...";
	    out.println(key + "=" + val);
	}
    }

    public static void main(String[] args) {
	PropertiesStore ps = new PropertiesStore();
	ps.put("hola", "Hola");
	ps.put("nombre", "SerGenis");
	ps.put("planeta", "Tierra");
	ps.put("soy.de", "Soy ${nombre} del planeta ${planeta}");
	ps.put("saludar", "${hola}. ${soy.de}. ¿Cómo te va?");
	ps.listRemplace(System.out);
    }
}
